#ifndef __WIZ_DATATYPE_POOL_HPP__SHANHAOBO_19800429__
#define __WIZ_DATATYPE_POOL_HPP__SHANHAOBO_19800429__

#include "../../Base/WizBase.hpp"

#include "../Container/WizDataTypeArray.hpp"
#include "../Container/WizDataTypeSet.hpp"

namespace Wiz
{
    namespace Pool
    {
        template <::Wiz::Size::Type EleSz, ::Wiz::UInt::Type InitCnt, ::Wiz::UInt::Type ExpCnt>
        class Base
        {
        protected:
            ::Wiz::Array::Type<::Wiz::Void::Ptr>  m_Unallocated;
            ::Wiz::Array::Type<::Wiz::Void::Ptr>  m_MemoryPool;
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
            ::Wiz::Set::Type<::Wiz::Void::Ptr>    m_Allocated;
#endif /*(WIZ_DEBUG_MODE == WIZ_CFG_TRUE)*/
        protected:
            Base()
            {
                this->Expand(InitCnt);
            }
            virtual ~Base()
            {
                this->Clear();
            }

        protected:
            ::Wiz::Bool::Type Expand(::Wiz::Int::In Count)
            {
                ::Wiz::Byte::Ptr BPtr = ::Wiz::Cast::Static<::Wiz::Byte::Ptr>(malloc(Count * EleSz));
                if (::Wiz::NotValidPtr(BPtr))
                {
                    throw ::Wiz::Exception::BadAlloc();
                    return ::Wiz::Bool::False;
                }
                m_MemoryPool.PushBack(BPtr);
                ::Wiz::Int::Type i;
                for (i = 0; i < Count; i++)
                {
                    m_Unallocated.PushBack(::Wiz::Cast::Static<::Wiz::Void::Ptr>(BPtr));
                    BPtr += EleSz;
                }
                return ::Wiz::Bool::True;
            }
            ::Wiz::Void::Type Clear()
            {
                ::Wiz::Array::Type<::Wiz::Void::Ptr>::tForEachIter  FE(m_MemoryPool);

                while (FE)
                {
                    free(*FE);
                }
                m_MemoryPool.Clear();
                m_Unallocated.Clear();
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                if (m_Allocated.Size() > 0)
                {
                    throw ::Wiz::Exception::RunTimeError("Memory Leak!");
                    return;
                }
#endif /*(WIZ_DEBUG_MODE == WIZ_CFG_TRUE)*/
            }
        protected:
            ::Wiz::Void::Ptr Allocate()
            {
                if (m_Unallocated.Size() > 0)
                {
                    ::Wiz::Void::Ptr VPtr = m_Unallocated.GetLast();
                    m_Unallocated.PopBack();
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                    m_Allocated.Insert(VPtr);
#endif /*(WIZ_DEBUG_MODE == WIZ_CFG_TRUE)*/
                    return VPtr;
                }

                if (Expand(ExpCnt))
                {
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                    ::Wiz::Void::Ptr VPtr = m_Unallocated.GetLast();
                    ::Wiz::Set::Type<::Wiz::Void::Ptr>::tIterator Found = m_Allocated.Find(VPtr);
                    if (Found != m_Allocated.End())
                    {
                        throw ::Wiz::Exception::RunTimeError("Memory was already allocated!");
                        return WIZ_NULLPTR;
                    }
                    m_Allocated.Insert(VPtr);
#endif /*(WIZ_DEBUG_MODE == WIZ_CFG_TRUE)*/

                    m_Unallocated.PopBack();

                    return VPtr;
                }

                return WIZ_NULLPTR;
            }
            ::Wiz::Void::Type Deallocate(::Wiz::Void::Ptr VPtr)
            {
#if (WIZ_DEBUG_MODE == WIZ_CFG_TRUE)
                ::Wiz::Set::Type<::Wiz::Void::Ptr>::tIterator Found = m_Allocated.Find(VPtr);
                if (Found == m_Allocated.End())
                {
                    throw ::Wiz::Exception::RunTimeError("Memory does not belong to this pool or Memory is not allocated!");
                    return;
                }
                m_Allocated.Erase(Found);
#endif /*(WIZ_DEBUG_MODE == WIZ_CFG_TRUE)*/
                m_Unallocated.PushBack(VPtr);
            }
        }; /// end of class Base

        template <class T, ::Wiz::UInt::Type InitCnt, ::Wiz::UInt::Type ExpCnt>
        class Type : public ::Wiz::Pool::Base<sizeof(T), InitCnt, ExpCnt>
        {
            typedef ::Wiz::Pool::Base<sizeof(T), InitCnt, ExpCnt> tSuper;
        public:
            Type() : tSuper()
            {
            }
            virtual ~Type(){}
        public:
            T* Allocate()
            {
                return ::Wiz::Cast::Static<T*>(tSuper::Allocate());
            }
            ::Wiz::Void::Type Deallocate(T* FPtr)
            {
                tSuper::Deallocate(::Wiz::Cast::Static<::Wiz::Void::Ptr>(FPtr));
            }
        }; /// end of class Type
    } /// end of namespace Pool
} /// end of namespace Wiz

#endif /*__WIZ_DATATYPE_POOL_HPP__SHANHAOBO_19800429__*/
